﻿using System;
using System.Collections.Generic;
using System.Linq;

using Moe.ECamel.Common.Entities;

namespace Moe.ECamel.Server.BL
{
	public class ItemReservationBL : ECamelBL
	{
		public ItemReservationBL(ECamelDataContext dataContext) 
			: base(dataContext)
		{
		}

		public ItemReservation GetFirstItemReservation(int itemId, int libraryId)
		{
			// Find a reservation of the specified item which is reserved for a customer of the same library and is marked first:
			return (from ir in dataContext.ItemReservations
					join c in dataContext.Customers on ir.CustomerId equals c.CustomerId
					where ir.ItemId == itemId && c.LibraryId == libraryId && ir.IsFirst
					select ir).SingleOrDefault();
		}

		public ItemReservation GetLastItemReservation(int itemId, int libraryId)
		{
			// Find a reservation of the specified item which is reserved for a customer of the same library and has no subsequent reservation:
			return (from ir in dataContext.ItemReservations
					join c in dataContext.Customers on ir.CustomerId equals c.CustomerId
					where ir.ItemId == itemId && c.LibraryId == libraryId && ir.NextItemReservationId == null
					select ir).SingleOrDefault();
		}

		public ItemReservation GetSuccessor(ItemReservation itemReservation)
		{
			if (itemReservation.NextItemReservationId == null)
				return null;

			return (from ir in dataContext.ItemReservations
					where ir.ItemReservationId == itemReservation.NextItemReservationId
					select ir).Single();
		}

		public void CreateItemReservation(int itemId, int customerId, DateTime createdOn, ItemReservation precedingReservation)
		{
			// Create a new reservation:
			var reservation = new ItemReservation {ItemId = itemId, CustomerId = customerId, RequestedOn = createdOn};
			// If there's no preceding reservation, this new reservation is the first:
			reservation.IsFirst = precedingReservation == null;
			// If there's a preceding reservation, it successor (if any) is now the new reservation's successor.
			reservation.NextItemReservationId = precedingReservation != null ? precedingReservation.NextItemReservationId : null;
			// Insert:
			dataContext.ItemReservations.InsertOnSubmit(reservation);
			// If there is a predecessor, update its successor to this new reservation:
			if (precedingReservation != null)
				precedingReservation.NextItemReservation = reservation;
		}

		public void DeleteItemReservation(ItemReservation itemReservation)
		{
			// Find predecessor, if any:
			var predecessor = (from ir in dataContext.ItemReservations
			                   where ir.NextItemReservationId == itemReservation.ItemReservationId
			                   select ir).SingleOrDefault();
			// Find successor, if any:
			var successor = GetSuccessor(itemReservation);

			// Update predecessor:
			if (predecessor != null)
				predecessor.NextItemReservationId = successor != null ? successor.ItemReservationId : (int?)null;

			// Update successor:
			if (successor != null)
			{
				if (itemReservation.IsFirst)
					successor.IsFirst = true;
			}

			dataContext.ItemReservations.DeleteOnSubmit(itemReservation);
		}

		public ItemReservation GetAvailableItemReservation(int itemId, int customerId)
		{
			return (from ir in dataContext.ItemReservations
					where ir.ItemId == itemId && ir.CustomerId == customerId && ir.ReservedInventoryId != null
					select ir).FirstOrDefault();
		}

		public IList<ItemReservation> GetOverdueReservations(DateTime date)
		{
			return (from ir in dataContext.ItemReservations
			        where ir.ReservedInventoryId != null && ir.ReservedUntil <= date
			        select ir).ToList();
		}
	}
}
